package com.hundsun.yr.universal.library.widget;

import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.animation.Animator.AnimatorListener;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;

import com.hundsun.yr.universal.library.R;
import com.hundsun.yr.universal.library.common.DensityUtils;
import com.hundsun.yr.universal.library.utils.ViewUtils;

/**
 * @Title: HSCircularProgressBar.java
 * @Description: 自定义进度条
 * @date 2015-12-11 下午1:46:30
 * @author:hejun.shen
 * @email:shenhj15971@hundsun.com
 * @replace author:
 * @replace date:
 * @version V1.0
 */
public class HSCircularProgressBar extends View {


	/**
	 * 是否顺时针旋转
	 */
	private boolean mIsClockwise=true;
	/**
	 * 是否绘制标识(false时不占位)
	 */
	private boolean mMarker_draw=true;
	/**
	 * 用于保存配置更改的状态
	 */
	private static final String INSTANCE_STATE_SAVEDSTATE = "saved_state";

	/**
	 * used to save the progress on configuration changes
	 */
	private static final String INSTANCE_STATE_PROGRESS = "progress";

	/**
	 * used to save the marker progress on configuration changes
	 */
	private static final String INSTANCE_STATE_MARKER_PROGRESS = "marker_progress";

	/**
	 * used to save the background color of the progress
	 */
	private static final String INSTANCE_STATE_PROGRESS_BACKGROUND_COLOR = "progress_background_color";

	/**
	 * used to save the color of the progress
	 */
	private static final String INSTANCE_STATE_PROGRESS_COLOR = "progress_color";

	/**
	 * used to save and restore the visibility of the marker in this instance
	 */
	private static final String INSTANCE_STATE_MARKER_VISIBLE = "marker_visible";

	/**
	 * The rectangle enclosing the circle.
	 */
	private final RectF mCircleBounds = new RectF();

	/**
	 * the paint for the background.
	 */
	private Paint mBackgroundColorPaint = new Paint();

	/**
	 * The stroke width used to paint the circle.
	 */
	private int mCircleStrokeWidth = 10;

	/**
	 * The gravity of the view. Where should the Circle be drawn within the
	 * given bounds
	 * 
	 * {@link #computeInsets(int, int)}
	 */
	private int mGravity = Gravity.CENTER;

	/**
	 * The Horizontal inset calcualted in {@link #computeInsets(int, int)}
	 * depends on {@link #mGravity}.
	 */
	private int mHorizontalInset = 0;

	/**
	 * true if not all properties are set. then the view isn't drawn and there
	 * are no errors in the LayoutEditor
	 */
	private boolean mIsInitializing = true;

	/**
	 * flag if the marker should be visible
	 */
	private boolean mIsMarkerEnabled = true;

	/**
	 * 标识文字 paint
	 */
	private Paint mMarkerTextPaint;
	/**
	 * 标识文字颜色
	 */
	private int mMarkerTextColor = Color.WHITE;

	/**
	 * 标识文字大小
	 */
	private int mMarkerTextSize = 36;

	/**
	 * The Marker progress.
	 */
	private float mMarkerProgress = 0.0f;

	/**
	 * 标识 paint.
	 */
	private Paint mMarkerColorPaint = new Paint();

	/**
	 * 标识 x坐标.
	 * 
	 * 位置不是旋转拇指的位置。位置只计算在{@link #onMeasure(int, int)}
	 */
	private float mMarkerPosX;

	/**
	 * 标识 y坐标.
	 * 
	 * 位置不是旋转拇指的位置。位置只计算在{@link #onMeasure(int, int)}
	 */
	private float mMarkerPosY;

	/**
	 * The pointer width (in pixels).
	 */
	private int mMarkerRadius = 20;

	/**
	 * the overdraw is true if the progress is over 1.0.
	 */
	private boolean mOverrdraw = false;

	/**
	 * 进度
	 */
	private float mProgress = 0.3f;

	/**
	 * 进度
	 */
	private String mProgressStr = "30%";

	/**
	 * progress 背景颜色.
	 */
	private int mProgressBackgroundColor;

	/**
	 * progress 颜色
	 */
	private int mProgressColor;

	/**
	 * paint for the progress.
	 */
	private Paint mProgressColorPaint;

	/**
	 * 大圆的半径
	 * 
	 */
	private float mRadius;

	/**
	 * The Translation offset x which gives us the ability to use our own
	 * coordinates system.
	 */
	private float mTranslationOffsetX;

	/**
	 * The Translation offset y which gives us the ability to use our own
	 * coordinates system.
	 */
	private float mTranslationOffsetY;

	/**
	 * The Vertical inset calcualted in {@link #computeInsets(int, int)} depends
	 * on {@link #mGravity}..
	 */
	private int mVerticalInset = 0;
	/**
	 * 是否显示小圆
	 */
	private boolean mMarkerVisiable = true;

	/**
	 * 实例化一个新的HSCircularProgress
	 * 
	 * @param context 
	 */
	public HSCircularProgressBar(final Context context) {
		this(context, null);
	}

	/**
	 * 实例化一个新的HSCircularProgress
	 * 
	 * @param context the context
	 * @param attrs the attrs
	 */
	public HSCircularProgressBar(final Context context, final AttributeSet attrs) {
		this(context, attrs, 0);
	}

	/**
	 * 实例化一个新的HSCircularProgress
	 * 
	 * @param context  
	 * @param attrs  
	 * @param defStyle   
	 */
	public HSCircularProgressBar(final Context context,final AttributeSet attrs, final int defStyle) {
		super(context, attrs, defStyle);

		mMarkerTextSize=DensityUtils.sp2px(context, 12);
		// load the styled attributes and set their properties
		final TypedArray attributes = context.obtainStyledAttributes(attrs,
				R.styleable.HSCircularProgressBar, defStyle, 0);
		if (attributes != null) {
			try {
				setProgressColor(attributes.getColor(
						R.styleable.HSCircularProgressBar_progress_color,Color.CYAN));
				setProgressBackgroundColor(attributes.getColor(
								R.styleable.HSCircularProgressBar_progress_background_color,Color.GRAY));
				setProgress(attributes.getFloat(
						R.styleable.HSCircularProgressBar_progress, 0.0f));
				setMarkerProgress(attributes.getFloat(
								R.styleable.HSCircularProgressBar_marker_progress,0.0f));
				setWheelSize((int) attributes.getDimension(
						R.styleable.HSCircularProgressBar_stroke_width, 10));
				setMarkerEnabled(attributes.getBoolean(
						R.styleable.HSCircularProgressBar_marker_visible, true));
				setMarkerDraw(attributes.getBoolean(
						R.styleable.HSCircularProgressBar_marker_draw, true));
				mGravity = attributes.getInt(
						R.styleable.HSCircularProgressBar_android_gravity,Gravity.CENTER);
			} finally {
				// make sure recycle is always called.
				attributes.recycle();
			}
		}

		updateBackgroundColor();

		updateMarker();

		updateProgressColor();

		// the view has now all properties and can be drawn
		mIsInitializing = false;

	}

	/**
	 * Compute insets.
	 * 
	 * <pre>
	 *  ______________________
	 * |_________dx/2_________|
	 * |......| /'''''\|......|
	 * |-dx/2-|| View ||-dx/2-|
	 * |______| \_____/|______|
	 * |________ dx/2_________|
	 * </pre>
	 * 
	 * @param dx
	 *            the dx the horizontal unfilled space
	 * @param dy
	 *            the dy the horizontal unfilled space
	 */
	@SuppressLint("NewApi")
	private void computeInsets(final int dx, final int dy) {
		int absoluteGravity = mGravity;
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
			absoluteGravity = Gravity.getAbsoluteGravity(mGravity,getLayoutDirection());
		}

		switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
		case Gravity.LEFT:
			mHorizontalInset = 0;
			break;
		case Gravity.RIGHT:
			mHorizontalInset = dx;
			break;
		case Gravity.CENTER_HORIZONTAL:
		default:
			mHorizontalInset = dx / 2;
			break;
		}
		switch (absoluteGravity & Gravity.VERTICAL_GRAVITY_MASK) {
		case Gravity.TOP:
			mVerticalInset = 0;
			break;
		case Gravity.BOTTOM:
			mVerticalInset = dy;
			break;
		case Gravity.CENTER_VERTICAL:
		default:
			mVerticalInset = dy / 2;
			break;
		}
	}

	public int getCircleStrokeWidth() {
		return mCircleStrokeWidth;
	}

	/**
	 * Gets the current rotation.
	 * 
	 * @return the current rotation
	 */
	private float getCurrentRotation() {
		return 360 * mProgress;
	}

	/**
	 * similar to {@link #getProgress}
	 */
	public float getMarkerProgress() {
		return mMarkerProgress;
	}

	/**
	 * gives the current progress of the ProgressBar. Value between 0..1 if you
	 * set the progress to >1 you'll get progress % 1 as return value
	 * 
	 * @return the progress
	 */
	public float getProgress() {
		return mProgress;
	}

	/**
	 * Gets the progress color.
	 * 
	 * @return the progress color
	 */
	public int getProgressColor() {
		return mProgressColor;
	}

	

	/**
	 * @return 标识是否可见
	 */
	public boolean isMarkerEnabled() {
		return mIsMarkerEnabled;
	}
	
	/**
	 * @return 是否顺时针绘制
	 */
	public boolean isClockwise() {
		return mIsClockwise;
	}
	
	/**
	 * @return 标识是否占位
	 */
	public boolean isMarker_draw() {
		return mMarker_draw;
	}
	
	
	
	/**
	 * 是顺时针绘制
	 * 
	 * @param enabled
	 *            新的标识状态
	 */
	public void setClockwise(final boolean isClockwise) {
		mIsClockwise = isClockwise;
	}


	@SuppressLint("DrawAllocation")
	@Override
	protected void onDraw(final Canvas canvas) {

		// All of our positions are using our internal coordinate system.
		// Instead of translating
		// them we let Canvas do the work for us.
		canvas.translate(mTranslationOffsetX, mTranslationOffsetY);

		final float progressRotation = getCurrentRotation();
		
		
		if(mIsClockwise){
			// draw the background
			if (!mOverrdraw) {
				canvas.drawArc(mCircleBounds, 90, -(360 - progressRotation), false,mBackgroundColorPaint);
			}
			
			// draw the progress or a full circle if overdraw is true
			canvas.drawArc(mCircleBounds, 90, mOverrdraw ? 360 : progressRotation,false, mProgressColorPaint);
			
			if (mIsMarkerEnabled) {
				
				canvas.save();
				canvas.rotate(progressRotation + 90);
				// rotate the square by 45 degrees
				canvas.rotate(45, mMarkerPosX, mMarkerPosY);
				canvas.drawCircle(mMarkerPosX, mMarkerPosY,ViewUtils.getFontWidth(mMarkerTextPaint, mProgressStr) / 2 ,mMarkerColorPaint);
				canvas.restore();
				
				canvas.save();
				canvas.rotate(progressRotation + 90);
				
				canvas.rotate(-progressRotation - 90, mMarkerPosX, mMarkerPosY);
				//mMarkerPosY-((mMarkerTextPaint.descent() + mMarkerTextPaint.ascent()) / 2) text Y轴坐标
				canvas.drawText(mProgressStr, mMarkerPosX, mMarkerPosY-((mMarkerTextPaint.descent() + mMarkerTextPaint.ascent()) / 2) , mMarkerTextPaint);
				canvas.restore();
				
			}else{
				if(mMarkerVisiable&&progressRotation==0){
					canvas.save();
					canvas.rotate(progressRotation + 90);
					// rotate the square by 45 degrees
					canvas.rotate(45, mMarkerPosX, mMarkerPosY);
					canvas.drawCircle(mMarkerPosX, mMarkerPosY,(int)mCircleStrokeWidth / 2f,mMarkerColorPaint);
					canvas.restore();
				}
				
			}
			
		}else{
			// draw the background
	        if (!mOverrdraw) {
	            canvas.drawArc(mCircleBounds, 270, 360, false,mBackgroundColorPaint);
	        }
			
			// draw the progress or a full circle if overdraw is true
	        canvas.drawArc(mCircleBounds, 270, mOverrdraw ? 360 : (-progressRotation), false,
	                mProgressColorPaint);
			
			if (mIsMarkerEnabled) {
				
				canvas.save();
				
				canvas.rotate(-progressRotation - 90);
				// rotate the square by 45 degrees
				canvas.rotate(45, mMarkerPosX, mMarkerPosY);
				canvas.drawCircle(mMarkerPosX, mMarkerPosY,ViewUtils.getFontWidth(mMarkerTextPaint, mProgressStr) / 2 ,mMarkerColorPaint);
				canvas.restore();
				
				canvas.save();
				canvas.rotate(-progressRotation - 90);
				canvas.rotate(progressRotation + 90, mMarkerPosX, mMarkerPosY);
				canvas.drawText(mProgressStr, mMarkerPosX, mMarkerPosY-((mMarkerTextPaint.descent() + mMarkerTextPaint.ascent()) / 2), mMarkerTextPaint);
				canvas.restore();
				
			}else{
				if(mMarkerVisiable&&progressRotation==0){
					canvas.save();
					
					canvas.rotate(-progressRotation - 90);
					// rotate the square by 45 degrees
					canvas.rotate(45, mMarkerPosX, mMarkerPosY);
					canvas.drawCircle(mMarkerPosX, mMarkerPosY,(int)mCircleStrokeWidth / 2f ,mMarkerColorPaint);
					canvas.restore();
				}
			}
		}

	}

	@Override
	protected void onMeasure(final int widthMeasureSpec,
			final int heightMeasureSpec) {
		final int height = getDefaultSize(getSuggestedMinimumHeight()
				+ getPaddingTop() + getPaddingBottom(), heightMeasureSpec);
		final int width = getDefaultSize(getSuggestedMinimumWidth()
				+ getPaddingLeft() + getPaddingRight(), widthMeasureSpec);

		final int diameter;
		if (heightMeasureSpec == MeasureSpec.UNSPECIFIED) {
			// ScrollView
			diameter = width;
			computeInsets(0, 0);
		} else if (widthMeasureSpec == MeasureSpec.UNSPECIFIED) {
			// HorizontalScrollView
			diameter = height;
			computeInsets(0, 0);
		} else {
			// Default
			diameter = Math.min(width, height);
			computeInsets(width - diameter, height - diameter);
		}

		setMeasuredDimension(diameter, diameter);

		mMarkerRadius = (int) (ViewUtils.getFontWidth(mMarkerTextPaint, "99%") +(int)mCircleStrokeWidth / 2f);

		
		float halfWidth = diameter * 0.5f;

		// width of the drawed circle (+ the drawedMarker)
		float drawedWith;
		if(isMarker_draw()){
			drawedWith = mMarkerRadius ;
//		if (isMarkerEnabled()) {
//			drawedWith = mMarkerRadius ;
//		} else {
////		drawedWith = mCircleStrokeWidth / 2f;
//			drawedWith = mMarkerRadius ;
//		}
			
		}else{
			drawedWith = mCircleStrokeWidth / 2f;
		}
		

		// -0.5f for pixel perfect fit inside the viewbounds
		mRadius = halfWidth - drawedWith - 0.5f;

		mCircleBounds.set(-mRadius, -mRadius, mRadius, mRadius);

		mMarkerPosX = (float) (mRadius * Math.cos(0));
		mMarkerPosY = (float) (mRadius * Math.sin(0));

		mTranslationOffsetX = halfWidth + mHorizontalInset;
		mTranslationOffsetY = halfWidth + mVerticalInset;

	}

	@Override
	protected void onRestoreInstanceState(final Parcelable state) {
		if (state instanceof Bundle) {
			final Bundle bundle = (Bundle) state;
			setProgress(bundle.getFloat(INSTANCE_STATE_PROGRESS));
			setMarkerProgress(bundle.getFloat(INSTANCE_STATE_MARKER_PROGRESS));

			final int progressColor = bundle.getInt(INSTANCE_STATE_PROGRESS_COLOR);
			if (progressColor != mProgressColor) {
				mProgressColor = progressColor;
				updateProgressColor();
			}

			final int progressBackgroundColor = bundle.getInt(INSTANCE_STATE_PROGRESS_BACKGROUND_COLOR);
			if (progressBackgroundColor != mProgressBackgroundColor) {
				mProgressBackgroundColor = progressBackgroundColor;
				updateBackgroundColor();
			}

			mIsMarkerEnabled = bundle.getBoolean(INSTANCE_STATE_MARKER_VISIBLE);

			super.onRestoreInstanceState(bundle.getParcelable(INSTANCE_STATE_SAVEDSTATE));
			return;
		}

		super.onRestoreInstanceState(state);
	}

	@Override
	protected Parcelable onSaveInstanceState() {
		final Bundle bundle = new Bundle();
		bundle.putParcelable(INSTANCE_STATE_SAVEDSTATE,
				super.onSaveInstanceState());
		bundle.putFloat(INSTANCE_STATE_PROGRESS, mProgress);
		bundle.putFloat(INSTANCE_STATE_MARKER_PROGRESS, mMarkerProgress);
		bundle.putInt(INSTANCE_STATE_PROGRESS_COLOR, mProgressColor);
		bundle.putInt(INSTANCE_STATE_PROGRESS_BACKGROUND_COLOR,mProgressBackgroundColor);
		bundle.putBoolean(INSTANCE_STATE_MARKER_VISIBLE, mIsMarkerEnabled);
		return bundle;
	}

	/**
	 * 设置Marker颜色
	 * 
	 * @param color
	 */
	public void setMarkerColor(final int color) {
		mMarkerTextColor = color;

		updateMarker();
	}

	/**
	 * 是否显示标识
	 * 
	 * @param enabled
	 *            新的标识状态
	 */
	public void setMarkerEnabled(final boolean enabled) {
		mIsMarkerEnabled = enabled;
		mMarkerVisiable  = enabled;
	}
	
	
	/**
	 * 标识是否占位
	 * 
	 * @param enabled
	 *            新的标识状态
	 */
	public void setMarkerDraw(final boolean marker_draw) {
		mMarker_draw = marker_draw;
	}
	

	/**
	 * 设置标识进度 progress.
	 * 
	 * @param progress
	 *            新标识进度
	 */
	public void setMarkerProgress(final float progress) {
		if(progress>=1||progress<=0){
			mIsMarkerEnabled = true;
		}else if(mMarkerVisiable){
			mIsMarkerEnabled = true;
		}else{
			mIsMarkerEnabled = false;
			
		}
		mMarkerProgress = progress;
		updateMarker();
	}

	
	public void setMarkerTextSize(int textSize){
		mMarkerTextSize=textSize;
		updateMarker();
	}
	
	/**
	 * 设置进度 progress.
	 * 
	 * @param progress  新进度
	 */
	public void setProgress(final float progress) {
		if (progress == mProgress) {
			return;
		}
		
		if(progress>=1||progress<=0){
			mIsMarkerEnabled = false;
		}else if(mMarkerVisiable){
			mIsMarkerEnabled = true;
		}else{
			mIsMarkerEnabled = false;
			
		}

		if (progress == 1) {
			mOverrdraw = false;
			mProgress = 1;
		} else {

			if (progress >= 1) {
				mOverrdraw = true;
			} else {
				mOverrdraw = false;
			}

			mProgress = progress % 1.0f;
		}
		mProgressStr = String.valueOf((int) (mProgress * 100)) + "%";
		
		
		

		if (!mIsInitializing) {
			invalidate();
		}
	}

	/**
	 * 设置progress 背景 颜色
	 * 
	 * @param color  新的progress背景颜色
	 */
	public void setProgressBackgroundColor(final int color) {
		mProgressBackgroundColor = color;

		updateMarker();
		updateBackgroundColor();
	}

	/**
	 * 设置progress 颜色
	 * 
	 * @param color  新的progress颜色
	 */
	public void setProgressColor(final int color) {
		mProgressColor = color;

		updateProgressColor();
	}

	/**
	 * Sets the wheel size.
	 * 
	 * @param dimension
	 *            the new wheel size
	 */
	public void setWheelSize(final int dimension) {
		mCircleStrokeWidth = dimension;

		// update the paints
		updateBackgroundColor();
		updateMarker();
		updateProgressColor();
	}

	/**
	 * 更新背景的 paint
	 */
	private void updateBackgroundColor() {
		mBackgroundColorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mBackgroundColorPaint.setColor(mProgressBackgroundColor);
		mBackgroundColorPaint.setStyle(Paint.Style.STROKE);
		mBackgroundColorPaint.setStrokeWidth(mCircleStrokeWidth);

		invalidate();
	}

	/**
	 * 更新marker的 paint
	 */
	private void updateMarker() {
		mMarkerTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mMarkerTextPaint.setColor(mMarkerTextColor);
		mMarkerTextPaint.setTextAlign(Paint.Align.CENTER);
		mMarkerTextPaint.setTextSize(mMarkerTextSize);
		mMarkerTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
		invalidate();
	}

	/**
	 * 更新Progress
	 */
	private void updateProgressColor() {
		mProgressColorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mProgressColorPaint.setColor(mProgressColor);
		mProgressColorPaint.setStyle(Paint.Style.STROKE);
		mProgressColorPaint.setStrokeWidth(mCircleStrokeWidth);

		mMarkerColorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mMarkerColorPaint.setColor(mProgressColor);
		mMarkerColorPaint.setStyle(Paint.Style.FILL_AND_STROKE);
		mMarkerColorPaint.setStrokeWidth(mCircleStrokeWidth);

		invalidate();
	}
	
	/**
	 * 执行动画
	 * @param listener 监听
	 * @param progress 进度
	 * @param duration 持续时间
	 */
	public void animate(AnimatorListener listener, final float progress, int duration) {
		// TODO Auto-generated method stub
		ObjectAnimator mProgressBarAnimator = ObjectAnimator.ofFloat(this, "progress", progress);
        mProgressBarAnimator.setDuration(Math.abs((long) (progress*duration)));
        mProgressBarAnimator.addListener(new AnimatorListener() {

            @Override
            public void onAnimationCancel(final Animator animation) {
            }

            @Override
            public void onAnimationEnd(final Animator animation) {
            	setMarkerProgress(progress);
                setProgress(progress);
            }

            @Override
            public void onAnimationRepeat(final Animator animation) {
            }

            @Override
            public void onAnimationStart(final Animator animation) {
            }
        });
        if (listener != null) {
            mProgressBarAnimator.addListener(listener);
        }
        mProgressBarAnimator.reverse();
        mProgressBarAnimator.addUpdateListener(new AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(final ValueAnimator animation) {
            	setProgress((Float) animation.getAnimatedValue());
            }
        });
        
        mProgressBarAnimator.start();
    }

}
